package com.lin.execute;

import com.lin.info.FontsField;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;

import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class XmlUtils {

    private static boolean isSimpleClassName = false;  // 是否使用简单类名
    private static List<String> urls;  // 需要使用简化类名的类路径

    // 设置是否使用简单类名以及设置URL列表
    public static void setSimpleClassName(boolean isSimpleClassName, List<String> urls) {
        XmlUtils.isSimpleClassName = isSimpleClassName;
        XmlUtils.urls = urls;
    }

    // 获取 classTag
    private static String getClassTag(Class<?> clazz) {
        if (isSimpleClassName) {
            String classPath = clazz.getName();
            if(isBasicType(clazz) || classPath.startsWith("java.util")) {
                return classPath;
            }
            for (String url : urls) {
                if (classPath.startsWith(url)) {
                    // 使用简化的类名
                    return clazz.getSimpleName();
                }
            }
            try {
                throw new Exception("包含未定义路径名:"+classPath);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        // 默认返回完整的类名
        return clazz.getName();
    }

    public static Class<?> getClassFromTag(String classTag) throws ClassNotFoundException {
        if (isSimpleClassName && urls != null && !urls.isEmpty()) {
            // 如果是简单类名且urls不为空
            for (String url : urls) {
                // 组合完整的类名
                String fullClassName = url + "." + classTag;
                try {
                    // 尝试加载这个类
                    return Class.forName(fullClassName);
                } catch (ClassNotFoundException e) {
                    // 如果没有找到该类，继续尝试下一个url
                    continue;
                }
            }
            // 如果找不到，抛出异常
            throw new ClassNotFoundException("Class not found with tag: " + classTag);
        } else {
            // 如果不是简化类名，直接使用classTag作为完整的类名
            return Class.forName(classTag);
        }
    }


    // 将对象转换为 XML
    public static String objectToXml(Object object) throws Exception {
        Document document = DocumentHelper.createDocument();
        Element root = document.addElement(object.getClass().getSimpleName());  // 根元素使用类名
        root.addAttribute("classTag", getClassTag(object.getClass()));  // 改为 classTag
        // 递归转换对象字段
        convertObjectToXml(root, object);
        // 格式化XML并返回
        return formatXml(document);
    }

    // 递归地将对象的字段转换为 XML
    private static void convertObjectToXml(Element parentElement, Object object) throws IllegalAccessException {
        if (object == null) return;

        Class<?> clazz = object.getClass();

        while (clazz != null) {

            // 遍历对象的所有字段
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);  // 设置可以访问私有字段

                if (field.isAnnotationPresent(FontsField.class)) {
                    String fieldName = field.getAnnotation(FontsField.class).name().isEmpty() ? field.getName() : field.getAnnotation(FontsField.class).name();
                    Object fieldValue = field.get(object);

                    // 如果字段值不为null，处理该字段
                    if (fieldValue != null) {
                        handleField(parentElement, fieldName, fieldValue);
                    }
                }
            }
            // 获取父类
            clazz = clazz.getSuperclass();
        }


    }

    // 处理字段的类型
    private static void handleField(Element parentElement, String fieldName, Object fieldValue) throws IllegalAccessException {
        if (fieldValue instanceof List) {
            // 如果字段是 List 类型，处理为多个子元素
            appendListElements(parentElement, fieldName, (List<?>) fieldValue);
        } else if (fieldValue instanceof Map) {
            // 如果字段是 Map 类型，处理为键值对
            appendMapElements(parentElement, fieldName, (Map<?, ?>) fieldValue);
        } else if (isBasicType(fieldValue.getClass())) {
            // 如果字段是基本类型，直接添加文本
            appendBasicField(parentElement, fieldName, fieldValue);
        } else {
            // 如果字段是自定义对象，递归处理
            appendClassBeanElement(parentElement, fieldName, fieldValue);
        }
    }

    // 判断是否是基本类型
    private static boolean isBasicType(Class<?> clazz) {
        return clazz.isPrimitive() || clazz == String.class || clazz == Integer.class || clazz == Long.class || clazz == Double.class
                || clazz == Float.class || clazz == Boolean.class || clazz == Character.class || clazz == Byte.class || clazz == Short.class;
    }

    // 处理 List 类型字段
    private static void appendListElements(Element parentElement, String fieldName, List<?> list) throws IllegalAccessException {
        // 创建一个外层的 list 标签
        Element listElement = parentElement.addElement(fieldName);  // 给 list 添加外层标签
        listElement.addAttribute("classTag", getClassTag(list.getClass())); // 为 list 标签添加 classTag 属性

        for (Object item : list) {
            if (item != null) {
                // 对于每个 list 项目，创建一个对应的元素
//                Element itemElement = listElement.addElement("item");
                if (isBasicType(item.getClass())) {
                    appendBasicField(listElement, fieldName, item);
                } else {
                    appendClassBeanElement(listElement, item.getClass().getSimpleName(), item);
                }
            }
        }
    }

    // 处理 Map 类型字段
    private static void appendMapElements(Element parentElement, String fieldName, Map<?, ?> map) {

        // 创建一个外层的 map 标签
        Element mapElement = parentElement.addElement(fieldName);  // 给 list 添加外层标签

        for (Map.Entry<?, ?> entry : map.entrySet()) {
            Element child = mapElement.addElement("map");
            if (entry.getKey() != null) {
                child.addElement("key").addText(entry.getKey().toString());
            }
            if (entry.getValue() != null) {
                child.addElement("value").addText(entry.getValue().toString());
            }
        }
    }

    // 处理基本类型字段
    private static void appendBasicField(Element parentElement, String fieldName, Object fieldValue) {
        Element fieldElement = parentElement.addElement(fieldName);
        fieldElement.addAttribute("classTag", getClassTag(fieldValue.getClass())); // 改为 classTag
        fieldElement.addText(fieldValue.toString());
    }

    // 处理 ClassBean 类型字段
    private static void appendClassBeanElement(Element parentElement, String fieldName, Object fieldValue) throws IllegalAccessException {
        Element classBeanElement = parentElement.addElement(fieldName);
        classBeanElement.addAttribute("classTag", getClassTag(fieldValue.getClass()));  // 改为 classTag
        convertObjectToXml(classBeanElement, fieldValue);
    }

    // 格式化 XML
    private static String formatXml(Document document) throws Exception {
        OutputFormat format = OutputFormat.createPrettyPrint();
        StringWriter writer = new StringWriter();
        XMLWriter xmlWriter = new XMLWriter(writer, format);
        xmlWriter.write(document);
        return writer.toString();
    }

    // 将 XML 转换为对象
    public static <T> T xmlToObject(String xml, Class<T> clazz) throws Exception {
        Document document = DocumentHelper.parseText(xml);
        Element root = document.getRootElement();
        return convertXmlToObject(root, clazz);
    }


    // 递归将 XML 转换为对象
    private static <T> T convertXmlToObject(Element element, Class<T> clazz) throws Exception {
        String classTag = element.attributeValue("classTag");
        Class<?> objectClass = getClassFromTag(classTag);  // 使用 classTag 获取类

        T object = (T) objectClass.getDeclaredConstructor().newInstance();  // 创建对象实例

        // 遍历 XML 元素的子元素
        for (Element childElement : element.elements()) {
            Field field = null;
            // 遍历类的继承链
            while (objectClass != null) {
                try {
                    // 获取当前类的字段
                    field = objectClass.getDeclaredField(childElement.getName());
                    // 设置字段可访问
                    field.setAccessible(true);
                    break;  // 成功找到字段后退出
                } catch (NoSuchFieldException e) {
                    // 如果当前类没有该字段，继续检查父类
                    objectClass = objectClass.getSuperclass();
                }
            }
            // 判断是否是基本类型
            assert field != null;
            if (isBasicType(field.getType())) {
                String text = childElement.getText();
                if (field.getType() == boolean.class || field.getType() == Boolean.class) {
                    // 特殊处理 boolean 类型，防止 null 值
                    field.set(object, text != null && !text.isEmpty() && Boolean.parseBoolean(text));
                } else {
                    field.set(object, convertStringToBasicType(childElement.getText(), field.getType()));
                }
            } else if (List.class.isAssignableFrom(field.getType())) {
                // 如果是 List 类型，递归处理
                List<?> list = convertXmlToList(childElement, field.getGenericType());
                field.set(object, list);
            } else if (Map.class.isAssignableFrom(field.getType())) {
                // 如果是 Map 类型，递归处理
                Map<?, ?> map = convertXmlToMap(childElement);
                field.set(object, map);
            } else {
                // 如果是自定义对象，递归转换
                Object nestedObject = convertXmlToObject(childElement, field.getType());
                field.set(object, nestedObject);
            }
        }

        return object;
    }

    // 将字符串转换为基本类型
    private static Object convertStringToBasicType(String text, Class<?> clazz) {
        if (clazz == String.class) return text;
        if (clazz == Integer.class || clazz == int.class) return Integer.parseInt(text);
        if (clazz == Long.class || clazz == long.class) return Long.parseLong(text);
        if (clazz == Double.class || clazz == double.class) return Double.parseDouble(text);
        if (clazz == Float.class || clazz == float.class) return Float.parseFloat(text);
        if (clazz == Boolean.class || clazz == boolean.class) return Boolean.parseBoolean(text);
        if (clazz == Character.class || clazz == char.class) return text.charAt(0);
        if (clazz == Byte.class || clazz == byte.class) return Byte.parseByte(text);
        if (clazz == Short.class || clazz == short.class) return Short.parseShort(text);
        return null;
    }

    // 将 XML 元素转换为 List
    private static <T> List<T> convertXmlToList(Element element, Type fieldType) throws Exception {
        List<T> list = new ArrayList<>();

        // 确保 fieldType 是 ParameterizedType (例如：List<T>)
        if (fieldType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) fieldType;
            Type actualType = parameterizedType.getActualTypeArguments()[0];

            // 处理 WildcardType
            if (actualType instanceof WildcardType) {
                WildcardType wildcardType = (WildcardType) actualType;
                Type[] upperBounds = wildcardType.getUpperBounds();
                if (upperBounds.length > 0) {
                    actualType = upperBounds[0];  // 使用上界类型
                }
            }

            // 遍历 XML 中的元素，处理每个子节点
            for (Element itemElement : element.elements()) {
                // 如果节点类型是 List，进行递归处理
                if (actualType instanceof ParameterizedType && List.class.isAssignableFrom((Class<?>) ((ParameterizedType) actualType).getRawType())) {
                    // 如果元素类型是 List，递归调用处理方法
                    list.add((T) convertXmlToList(itemElement, ((ParameterizedType) actualType).getActualTypeArguments()[0]));
                } else {
                    // 将当前元素转换为对象
                    T item = convertXmlToObject(itemElement, (Class<T>) actualType);
                    list.add(item);
                }
            }
        }
        return list;
    }

    // 将 XML 元素转换为 Map
    private static Map<String, String> convertXmlToMap(Element element) {
        Map<String, String> map = new HashMap<>();
        // 遍历 XML 元素的子元素并将键值对添加到 Map
        for (Element entryElement : element.elements()) {
            String key = entryElement.elementText("key");
            String value = entryElement.elementText("value");
            if (key != null && value != null) {
                map.put(key, value);
            }
        }
        return map;
    }
}
